﻿using Nop.Admin.Models.Directory;
using Nop.Core;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Directory;
using Nop.Services.Directory;
using Nop.Services.Localization;
using Nop.Services.Security;
using Nop.Web.Framework;
using Nop.Web.Framework.Controllers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Telerik.Web.Mvc;

namespace Nop.Admin.Controllers
{
    [AdminAuthorize]
    public partial class HolidayController : BaseNopController
    {
        #region Fields

        private readonly IHolidayService _holidayService;
        private readonly ILocalizationService _localizationService;
        private readonly IPermissionService _permissionService;
        private readonly AdminAreaSettings _adminAreaSettings;
        private readonly ICountryService _countryService;
        private readonly IStateProvinceService _stateProvinceService;

        #endregion

        #region Constructors

        public HolidayController(IHolidayService _holidayService,
            ILocalizationService localizationService,
            IPermissionService permissionService,
            IStateProvinceService stateProvinceService,
            ICountryService countryService,
            AdminAreaSettings adminAreaSettings)
        {
            this._localizationService = localizationService;
            this._holidayService = _holidayService;
            this._permissionService = permissionService;
            this._stateProvinceService = stateProvinceService;
            this._countryService = countryService;
            this._adminAreaSettings = adminAreaSettings;
        }

        #endregion

        #region Utilities

        private HolidayModel PrepareModel(Holiday holiday)
        {
            var model = new HolidayModel()
            {
                CountryCode = holiday.CountryCode,
                Id = holiday.Id,
                Name = holiday.Name,
                StateProvinces = holiday.StateProvinces.Count > 0 ? String.Join(",", holiday.StateProvinces.Select(x => x.Abbreviation)) : "Add states or provinces",
                Dates = holiday.Dates.Count > 0 ? String.Join(",", holiday.Dates.Select(d => d.Date.ToShortDateString())) : "Add dates",
                DisplayOrder = holiday.DisplayOrder,
                Description = holiday.Description
            };
            return model;
        }

        #endregion

        #region Holidays

        public ActionResult Index()
        {
            return RedirectToAction("List");
        }

        public ActionResult List()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return AccessDeniedView();

            var holidays = _holidayService.GetAllHolidays();
            var gridModel = new GridModel<HolidayModel>
            {
                Data = holidays.Select(PrepareModel),
                Total = holidays.Count()
            };
            return View(gridModel);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult List(GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return Content("Access denied.");

            var holidays = _holidayService.GetAllHolidays()
                .ForCommand(command)
                .ToList();
            var gridModel = new GridModel<HolidayModel>
            {
                Data = holidays.Select(PrepareModel),
                Total = holidays.Count()
            };
            return new JsonResult
            {
                Data = gridModel
            };
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult Create(HolidayModel model, GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return Content("Access denied.");

            if (!ModelState.IsValid)
            {
                //display the first model error
                var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage);
                return Content(modelStateErrors.FirstOrDefault());
            }

            var holiday = new Holiday()
            {
                Name = model.Name,
                Description = model.Description,
                DisplayOrder = model.DisplayOrder,
                CountryCode = model.CountryCode
            };


            _holidayService.InsertHoliday(holiday);

            return List(command);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult Edit(HolidayModel model, GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return Content("Access denied.");

            if (!ModelState.IsValid)
            {
                //display the first model error
                var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage);
                return Content(modelStateErrors.FirstOrDefault());
            }

            var holiday = _holidayService.GetHolidayById(model.Id);
            if (holiday == null)
                throw new NopException("No holiday found with the specified id {0}", model.Id);

            holiday.Name = model.Name;
            holiday.CountryCode = model.CountryCode;
            holiday.Description = model.Description;
            holiday.DisplayOrder = model.DisplayOrder;

            _holidayService.UpdateHoliday(holiday);

            return List(command);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult Delete(int id, GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return Content("Access denied.");

            var holiday = _holidayService.GetHolidayById(id);
            if (holiday == null)
                throw new NopException("No holiday found with the specified id {0}", id);

            _holidayService.DeleteHoliday(holiday);

            return List(command);
        }

        #region Dates

        public ActionResult Dates(int holidayId)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return Content("Access denied.");

            var holiday = _holidayService.GetHolidayById(holidayId);
            if (holiday == null)
            {
                return RedirectToAction("List");
            }

            ViewBag.HolidayId = holidayId;
            ViewBag.HolidayName = holiday.Name;

            var dates = holiday.Dates
                .OrderBy(h => h.Date)
                .ToList();
            var gridModel = new GridModel<HolidayDateModel>
            {
                Data = dates
                    .Take(_adminAreaSettings.GridPageSize)
                    .Select(x => new HolidayDateModel()
                    {
                        Id = x.Id,
                        HolidayId = holidayId,
                        Date = x.Date,
                        DateStr = x.Date.ToShortDateString()
                    }),
                Total = dates.Count
            };
            return View(gridModel);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult Dates(int holidayId, GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return Content("Access denied.");

            var holiday = _holidayService.GetHolidayById(holidayId);
            if (holiday == null)
            {
                return Content("The holiday cannot be found.");
            }

            var dates = holiday.Dates
                .OrderBy(h => h.Date)
                .Select(h => new HolidayDateModel()
                    {
                        Id = h.Id,
                        HolidayId = holidayId,
                        Date = h.Date,
                        DateStr = h.Date.ToShortDateString()
                    })
                .ForCommand(command)
                .ToList();

            var model = new GridModel<HolidayDateModel>
            {
                Data = dates.PagedForCommand(command),
                Total = dates.Count
            };
            return new JsonResult
            {
                Data = model
            };
        }

        [GridAction(EnableCustomBinding = true)]
        public ActionResult DateAdd(int holidayId, HolidayDate model, GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return Content("Access denied.");

            if (!ModelState.IsValid)
            {
                //display the first model error
                var modelStateErrors = this.ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage);
                return Content(modelStateErrors.FirstOrDefault());
            }

            var holiday = _holidayService.GetHolidayById(holidayId);
            if (holiday == null)
            {
                return Content("Holiday cannot be found.");
            }

            holiday.Dates.Add(new HolidayDate()
            {
                Date = model.Date,
                HolidayId = holidayId
            });

            _holidayService.UpdateHoliday(holiday);

            return Dates(model.HolidayId, command);
        }

        [GridAction(EnableCustomBinding = true)]
        public ActionResult DateDelete(int id, int holidayId, GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return Content("Access denied.");

            var holiday = _holidayService.GetHolidayById(holidayId);
            if (holiday == null)
            {
                return Content("Holiday cannot be found.");
            }

            var date = holiday.Dates.SingleOrDefault(h => h.Id == id);
            if (date == null)
            {
                return Content("The date cannot be found.");
            }

            _holidayService.DeleteDateById(id);

            return Dates(holidayId, command);
        }

        [GridAction(EnableCustomBinding = true)]
        public ActionResult DateEdit(HolidayDateModel model, GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return Content("Access denied.");

            var holiday = _holidayService.GetHolidayById(model.HolidayId);
            if (holiday == null)
            {
                return Content("Holiday cannot be found.");
            }

            var date = holiday.Dates.SingleOrDefault(h => h.Id == model.Id);
            if (date == null)
            {
                return Content("The date cannot be found.");
            }

            date.Date = model.Date;
            _holidayService.UpdateHoliday(holiday);

            return Dates(model.HolidayId, command);
        }

        #endregion

        #region StateProvinces

        public ActionResult StateProvinces(int holidayId)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return AccessDeniedView();

            var holiday = _holidayService.GetHolidayById(holidayId);
            if (holiday == null)
            {
                return RedirectToAction("List");
            }

            ViewBag.HolidayName = holiday.Name;

            //Get all published provinces in Canada
            //TODO: This is for Canada only at this point.
            var c = _countryService.GetCountryByTwoLetterIsoCode("CA");

            var sps = _stateProvinceService.GetStateProvincesByCountryId(c.Id);

            var model = sps.Select(x => x.ToModel()).ToList();
            model.ForEach(
                x => x.Selected = holiday.StateProvinces.Any(y => y.Id == x.Id));
            
            return View(model);
        }

        [HttpPost]
        public ActionResult StateProvinces(int holidayId, List<StateProvinceModel> model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCountries))
                return AccessDeniedView();

            var holiday = _holidayService.GetHolidayById(holidayId);
            if (holiday == null)
            {
                return RedirectToAction("List");
            }

            holiday.StateProvinces.Clear();
            model.Where(x => x.Selected)
                .ToList()
                .ForEach(x => holiday.StateProvinces.Add(
                    _stateProvinceService.GetStateProvinceById(x.Id)
                    ));

            _holidayService.UpdateHoliday(holiday);
            return RedirectToAction("List");
        }

        #endregion


        #endregion
    }
}
